﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FluentScript.CodeGen.Grammar
{
    /// <summary>
    /// Specifies a token.
    /// </summary>
    public class TokenSpec
    {
        public TokenSpec(int val, string kind, string text, string varname)
        {
            this.Value = val;
            this.Kind = kind;
            this.Text = text;
            this.VarName = varname;
        }


        public int Value { get; set; }
        public string Kind { get; set; }
        public string Text { get; set; }
        public string VarName { get; set; }
    }



    /// <summary>
    /// Specifies a type.
    /// </summary>
    public class TypeSpec
    {
        public TypeSpec(int val, string kind, string text, string varname)
        {
            this.Value = val;
            this.Kind = kind;
            this.Text = text;
            this.VarName = varname;
        }


        public int Value { get; set; }
        public string Kind { get; set; }
        public string Text { get; set; }
        public string VarName { get; set; }
    }



    /// <summary>
    /// Specifies all the supported builtin expressions.
    /// </summary>
    public class ExprSpec
    {
        public ExprSpec(string className, string name, string token, bool createPlugin, bool isStatement, bool isBlock, bool hasLhsRhs, bool createNewSymScope, bool hasOperator, object extraProps)
        {
            this.ClassName = className;
            this.Name = name;
            this.Token = token;
            this.IsStatement = IsStatement;
            this.IsBlock  = isBlock;  
            this.HasLhsRhs = hasLhsRhs;
            this.CreateNewSymScope = createNewSymScope;
            this.HasOperator      = hasLhsRhs;
            this.ExtraProps = extraProps;
        }


        public string ClassName { get; set; }
        public string Name { get; set; }
        public string Token { get; set; }
        public bool   IsStatement { get; set; }
        public bool   IsBlock           { get; set; }
        public bool   HasLhsRhs         { get; set; }
        public bool   CreateNewSymScope { get; set; }
        public bool   HasOperator       { get; set; }
        public object ExtraProps        { get; set; }
    }


    public class FSGrammarSpec
    {
        public List<TokenSpec> TokenSpecs { get; set; }
        public List<ExprSpec> ExprSpecs { get; set; }


        public void Setup()
        {
            this.TokenSpecs = new List<TokenSpec>()
            {
                new TokenSpec( 1,   "keyword",      "var"      ,    "Var"       ),
                new TokenSpec( 1,   "keyword",      "if"       ,    "If"        ),
                new TokenSpec( 1,   "keyword",      "while"    ,    "While"     ),
                new TokenSpec( 1,   "keyword",      "for"      ,    "For"       ),
                new TokenSpec( 1,   "keyword",      "try"      ,    "Try"       ),
                new TokenSpec( 1,   "keyword",      "catch"    ,    "Catch"     ),
                new TokenSpec( 1,   "keyword",      "return"   ,    "Return"    ),
                new TokenSpec( 1,   "keyword",      "function" ,    "Function"  ),
                new TokenSpec( 1,   "keyword",      "throw"    ,    "Throw"     ),
                new TokenSpec( 1,   "keyword",      "break"    ,    "Break"     ),
                new TokenSpec( 1,   "keyword",      "continue" ,    "Continue"  ),

                new TokenSpec(100,	"symbol", 	    "^"        ,    "Expo"),
                new TokenSpec(101,	"symbol", 	    "+"        ,    "Plus"),
                new TokenSpec(102,	"symbol", 	    "-"        ,    "Minus"),
                new TokenSpec(103,	"symbol", 	    "*"        ,    "Mult"),
                new TokenSpec(104,	"symbol", 	    "/"        ,    "Div"),
                new TokenSpec(105,	"symbol", 	    "%"        ,    "Mod"),
                new TokenSpec(106,	"symbol", 	    "="        ,    "Equals"),
                new TokenSpec(107,	"symbol", 	    "("        ,    "LeftParens"),
                new TokenSpec(108,	"symbol", 	    ")"        ,    "RightParens"),
                new TokenSpec(109,	"symbol", 	    "["        ,    "LeftBracket"),
                new TokenSpec(110,	"symbol", 	    "]"        ,    "RightBracket"),
                new TokenSpec(111,	"symbol", 	    "{"        ,    "LeftBrace"),
                new TokenSpec(112,	"symbol", 	    "}"        ,    "RightBrace"),
                new TokenSpec(113,	"symbol", 	    "\\"       ,    "Backslash"),
                new TokenSpec(114,	"symbol", 	    "!"        ,    "Exclamation"),
                new TokenSpec(115,	"symbol", 	    "@"        ,    "At"),
                new TokenSpec(116,	"symbol", 	    "#"        ,    "Pound"),
                new TokenSpec(117,	"symbol", 	    "$"        ,    "Dollar"),
                new TokenSpec(118,	"symbol", 	    ":"        ,    "Colon"),
                new TokenSpec(119,	"symbol", 	    ";"        ,    "Semicolon"),
                new TokenSpec(120,	"symbol", 	    "?"        ,    "Question"),
                new TokenSpec(121,	"symbol", 	    "<"        ,    "LessThan"),
                new TokenSpec(122,	"symbol", 	    ">"        ,    "MoreThan"),
                new TokenSpec(123,	"symbol", 	    "<="       ,    "LessThanEqual"),
                new TokenSpec(124,	"symbol", 	    ">="       ,    "MoreThanEqual"),
                new TokenSpec(125,	"symbol", 	    "!="       ,    "NotEqual"),
                new TokenSpec(126,	"symbol", 	    "=="       ,    "EqualEqual"),
                new TokenSpec(127,	"symbol", 	    "&&"       ,    "LogicAnd"),
                new TokenSpec(128,	"symbol", 	    "||"       ,    "LogicOr"),

                new TokenSpec( 1,   "literal",       "true"    ,    "True"),
                new TokenSpec( 1,   "literal",       "false"   ,    "False"),
                new TokenSpec( 1,   "literal",       "null"    ,    "Null"),
            };

            this.ExprSpecs = new List<ExprSpec>()
            {
                new ExprSpec("AssignExpr", 			"Assign", 			""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("AssignMultiExpr", 	"AssignMulti", 		""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("BinaryExpr", 			"Binary", 			""			,	false,      false	,	false	,	true	,	false	,	false	, null),
                new ExprSpec("CompareExpr", 		"Compare", 			""			,	false,      false	,	false	,	true	,	false	,	false	, null),
                new ExprSpec("ConditionExpr", 		"Condition", 		""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("ConstantExpr", 		"Constant", 		""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("FunctionCallExpr", 	"FunctionCall", 	""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("FunctionExpr", 		"Function", 		""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("IndexableExpr", 		"Indexable", 		""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("IndexExpr", 			"Index", 			""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("InterpolatedExpr", 	"Interpolated", 	""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("MapExpr", 			"Map", 				""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("MemberAccessExpr", 	"MemberAccess", 	""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("MemberExpr", 			"Member", 			""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("NamedParameterExpr", 	"NamedParameter", 	""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("NewExpr", 			"New", 				""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("ParameterExpr", 		"Parameter", 		""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("UnaryExpr", 			"Unary", 			""			,	false,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("VariableExpr", 		"Variable", 		"@ident"	,	true ,      false	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("BreakExpr", 			"Break", 			"break"		,	true ,      true	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("ContinueExpr", 		"Continue", 		"continue"	,	true ,      true	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("ForEachExpr", 		"ForEach", 			"for"		,	true ,      true	,	true	,	false	,	false	,	false	, null),
                new ExprSpec("ForExpr", 			"For", 				"for"		,	true ,      true	,	true	,	false	,	false	,	false	, null),
                new ExprSpec("FunctionDeclareExpr", "FunctionDeclare", 	"function"	,	true ,      true	,	true	,	false	,	false	,	false	, null),
                new ExprSpec("IfExpr", 				"If", 				"if"		,	true ,      true	,	true	,	false	,	false	,	false	, null),
                new ExprSpec("LambdaExpr", 			"Lambda", 			"function"	,	true ,      true	,	true	,	false	,	false	,	false	, null),
                new ExprSpec("ReturnExpr", 			"Return", 			"return"	,	true ,      true	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("ThrowExpr", 			"Throw", 			"throw"		,	true ,      true	,	false	,	false	,	false	,	false	, null),
                new ExprSpec("TryCatchExpr", 		"TryCatch", 		"try"		,	true ,      true	,	true	,	false	,	false	,	false	, null),
                new ExprSpec("WhileExpr", 			"While", 			"while"		,	true ,      true	,	true	,	false	,	false	,	false	, null),
            };

        }
    }
}
